package com.easylinkin.linkappapi.shigongyun.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Assert;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.easylinkin.linkappapi.device.entity.Device;
import com.easylinkin.linkappapi.jkmonior.entity.JkMonitorConfig;
import com.easylinkin.linkappapi.jkmonior.entity.JkMonitorItemConfig;
import com.easylinkin.linkappapi.jkmonior.mapper.JkMonitorConfigMapper;
import com.easylinkin.linkappapi.jkmonior.mapper.JkMonitorItemConfigMapper;
import com.easylinkin.linkappapi.security.context.LinkappUserContextProducer;
import com.easylinkin.linkappapi.security.entity.LinkappUser;
import com.easylinkin.linkappapi.shigongyun.dto.MonitorInfoDto;
import com.easylinkin.linkappapi.shigongyun.dto.MonitorInfoRecordDto;
import com.easylinkin.linkappapi.shigongyun.entity.JkMonitorInfo;
import com.easylinkin.linkappapi.shigongyun.entity.JkMonitorRecord;
import com.easylinkin.linkappapi.shigongyun.mapper.JkMonitorInfoMapper;
import com.easylinkin.linkappapi.shigongyun.mapper.JkMonitorRecordMapper;
import com.easylinkin.linkappapi.shigongyun.service.SiteMonitorService;
import com.easylinkin.linkappapi.shigongyun.vo.MonitorInfoVo;
import com.easylinkin.linkappapi.shigongyun.vo.MonitorPointDetailVo;
import com.easylinkin.linkappapi.shigongyun.vo.MonitorRecordVo;
import com.easylinkin.linkappapi.webcammanage.entity.DeviceAttributeStatus;
import com.easylinkin.linkappapi.webcammanage.mapper.DeviceAreaHandlerMapper;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import site.morn.rest.RestBuilders;
import site.morn.rest.RestMessage;

import javax.annotation.Resource;
import java.util.*;

/**
 * @author zhengwen
 **/
@Service
public class SiteMonitorServiceImpl implements SiteMonitorService {

    @Resource
    private JkMonitorInfoMapper monitorInfoMapper;

    @Resource
    private JkMonitorRecordMapper monitorRecordMapper;

    @Resource
    private DeviceAreaHandlerMapper deviceAreaHandlerMapper;

    @Resource
    private LinkappUserContextProducer linkappUserContextProducer;

    @Resource
    private JkMonitorItemConfigMapper jkMonitorItemConfigMapper;

    @Resource
    private JkMonitorConfigMapper jkMonitorConfigMapper;

    @Override
    public RestMessage latestMonitorDataTrend(MonitorInfoVo monitorInfoVo) {

        return null;
    }

    @Override
    public RestMessage realTimeMonitorData(MonitorInfoVo monitorInfoVo) {
        //增加租户划分
        LinkappUser linkappUser = linkappUserContextProducer.getNotNullCurrent();
        monitorInfoVo.setTenantId(linkappUser.getTenantId());

        //查询最新主记录
        MonitorInfoDto latestMonitorData = monitorInfoMapper.latestRealTimeMonitorData(monitorInfoVo);
        if (latestMonitorData == null) {
            return RestBuilders.failureBuilder().message("近7天没有监测数据，请联系相关责任人").build();
        }

        return RestBuilders.successBuilder().data(latestMonitorData).build();
    }

    @Override
    public IPage<DeviceAttributeStatus> getVideoList(Page page, Device device) {
        device.setTenantId(linkappUserContextProducer.getNotNullCurrent().getTenantId());
        List<DeviceAttributeStatus> list = deviceAreaHandlerMapper.getVideoTypeDeviceListGlobal(page, device);
        if (CollectionUtil.isEmpty(list)) {
            page.setTotal(0);
            page.setRecords(null);
            return page;
        }
        page.setRecords(list);
        return page;
    }

    @Override
    public List<DeviceAttributeStatus> getVideoInfo(String id) {
        List<DeviceAttributeStatus> deviceAttrInfoList = deviceAreaHandlerMapper.getVideoInfoByDeviceGlobal(
                id, null);
        return deviceAttrInfoList;
    }

    @Override
    public RestMessage getLatestMonitorNameList(MonitorInfoVo monitorInfoVo) {
        LinkappUser linkappUser = linkappUserContextProducer.getNotNullCurrent();

        //查询最新主记录
        QueryWrapper<JkMonitorInfo> infoQueryWrapper = new QueryWrapper<>();
        infoQueryWrapper.eq("tenant_id", linkappUser.getTenantId());
        infoQueryWrapper.eq(StringUtils.isNotBlank(monitorInfoVo.getProjectId()), "project_id",
                monitorInfoVo.getProjectId());
        infoQueryWrapper.ge(monitorInfoVo.getStartTime() != null, "create_time",
                monitorInfoVo.getStartTime());

        infoQueryWrapper.orderByDesc("create_time");
        infoQueryWrapper.last("limit 1");
        JkMonitorInfo latestMonitor = monitorInfoMapper.selectOne(infoQueryWrapper);

        //查询最新的监测项目名称
        if (latestMonitor != null) {
            Long infoId = latestMonitor.getId();
            if (infoId != null) {
                QueryWrapper<JkMonitorRecord> recordQueryWrapper = new QueryWrapper<>();
                recordQueryWrapper.eq("info_id", infoId);
                //recordQueryWrapper.isNull("parent_id");  如果只要监测项，可以加上
                List<JkMonitorRecord> recordList = monitorRecordMapper.selectList(recordQueryWrapper);
                return RestBuilders.successBuilder().data(recordList).build();
            }
        }

        return RestBuilders.successBuilder().data(null).build();
    }

    @Override
    public RestMessage getMonitorKxData(MonitorRecordVo monitorRecordVo) {
        LinkappUser linkappUser = linkappUserContextProducer.getNotNullCurrent();
        String tenantId = linkappUser.getTenantId();
        monitorRecordVo.setTenantId(tenantId);

        String pointName = monitorRecordVo.getPointName();
        Assert.isTrue(StringUtils.isNotBlank(pointName), "基坑监测点为空");
        String rangeType = monitorRecordVo.getRangeType();
        Assert.isTrue(StringUtils.isNotBlank(rangeType), "数据时间区间类型为空");
        Integer stepNum = monitorRecordVo.getStepNum();
        Assert.notNull(stepNum, "时间间隔为空");

        //组织时间范围
        initDateRange(rangeType, monitorRecordVo);

        //查询数据
        List<MonitorInfoRecordDto> recordList = monitorRecordMapper.selectInfRecordDtoBy(
                monitorRecordVo);
        //数据过滤补全
        Map<String, MonitorInfoRecordDto> mp = transCleanData(rangeType, stepNum, recordList,
                monitorRecordVo);

        return RestBuilders.successBuilder().data(mp).build();
    }

    @Override
    public RestMessage getLatestMonitorPointNameList(MonitorInfoVo monitorInfoVo) {
        //查询最新的监测项目名称
        Long measurementId = monitorInfoVo.getMeasurementId();
        if (measurementId != null) {
            QueryWrapper<JkMonitorRecord> recordQueryWrapper = new QueryWrapper();
            recordQueryWrapper.lambda().and(i -> i.eq(JkMonitorRecord::getParentId, measurementId).or()
                    .eq(JkMonitorRecord::getId, measurementId));

            List<JkMonitorRecord> recordList = monitorRecordMapper.selectList(recordQueryWrapper);
            return RestBuilders.successBuilder().data(recordList).build();
        }
        return RestBuilders.successBuilder().data(null).build();
    }

    @Override
    public RestMessage getPointDetail(MonitorRecordVo monitorRecordVo) {
        Assert.isTrue(StringUtils.isNotEmpty(monitorRecordVo.getPointCode()),"监测点编码为空");
        Assert.isTrue(StringUtils.isNotEmpty(monitorRecordVo.getPointName()),"监测点名称为空");

        LinkappUser linkappUser = linkappUserContextProducer.getNotNullCurrent();
        String tenantId = linkappUser.getTenantId();

        MonitorPointDetailVo vo = new MonitorPointDetailVo();

        //查询基本配置
        JkMonitorConfig config = null;
        QueryWrapper<JkMonitorConfig> configQw = new QueryWrapper<>();
        configQw.eq("tenant_id", tenantId);
        configQw.eq("delete_state", 1);
        configQw.orderByDesc("create_time");
        configQw.last(" limit 1");
        List<JkMonitorConfig> configList = jkMonitorConfigMapper.selectList(configQw);
        if (CollectionUtil.isNotEmpty(configList)) {
            config = configList.get(0);
        }

        //查询测点信息
        QueryWrapper<JkMonitorItemConfig> itemQw = new QueryWrapper<>();
        itemQw.eq("tenant_id", tenantId);
        itemQw.eq("delete_state", 1);
        itemQw.eq("item_code", monitorRecordVo.getPointCode());
        itemQw.eq("item_name", monitorRecordVo.getPointName());
        itemQw.orderByDesc("create_time");
        itemQw.last(" limit 1");
        List<JkMonitorItemConfig> itemList = jkMonitorItemConfigMapper.selectList(itemQw);
        if (CollectionUtil.isNotEmpty(itemList)){
            JkMonitorItemConfig pointInfo = itemList.get(0);
            vo.setPointInfo(pointInfo);
            //查询测项信息
            Integer parentId = pointInfo.getParentId();
            if (parentId.intValue() == 0){
                vo.setItemInfo(pointInfo);
            }else{
                JkMonitorItemConfig itemInfo = jkMonitorItemConfigMapper.selectById(parentId);
                vo.setItemInfo(itemInfo);
            }
        }
        //查询最新监测数据
        QueryWrapper<JkMonitorRecord> recordQw = new QueryWrapper<>();
        if(config != null){
            recordQw.eq("project_id",config.getProjectId());
        }
        //recordQw.eq("measurement_project_name",monitorRecordVo.getPointName());
        recordQw.eq("measurement_project_name",vo.getItemInfo().getItemName());
        recordQw.eq("point_name",monitorRecordVo.getPointCode());
        Date now = DateUtil.date();
        recordQw.ge("storage_time",DateUtil.format(DateUtil.offsetDay(DateUtil.beginOfDay(now),-30), DatePattern.NORM_DATETIME_PATTERN));
        recordQw.le("storage_time",DateUtil.format(DateUtil.endOfDay(now), DatePattern.NORM_DATETIME_PATTERN));
        recordQw.orderByDesc("storage_time");
        recordQw.last(" limit 1");
        List<JkMonitorRecord> recordList = monitorRecordMapper.selectList(recordQw);
        if (CollectionUtil.isNotEmpty(recordList)) {
            vo.setRecord(recordList.get(0));
        }

        return RestBuilders.successBuilder().data(vo).build();
    }

    @Override
    public List<DeviceAttributeStatus> getConfigVideoInfo() {
        LinkappUser linkappUser = linkappUserContextProducer.getNotNullCurrent();
        String tenantId = linkappUser.getTenantId();

        QueryWrapper<JkMonitorConfig> qw = new QueryWrapper<>();
        qw.eq("tenant_id",tenantId);
        List<JkMonitorConfig> configList = jkMonitorConfigMapper.selectList(qw);
        if(CollectionUtil.isNotEmpty(configList)){
            JkMonitorConfig config = configList.get(0);
            List<DeviceAttributeStatus> deviceAttrInfoList = deviceAreaHandlerMapper.getVideoInfoByDeviceGlobal(
                    config.getSiteVideoDeviceId(), null);
            return deviceAttrInfoList;
        }
        return null;
    }

    /**
     * 数据转换清理
     *
     * @param rangeType       时间区间类型
     * @param stepNum         间隔值
     * @param recordList      记录list
     * @param monitorRecordVo
     * @return 记录list
     */
    private Map<String, MonitorInfoRecordDto> transCleanData(String rangeType, Integer stepNum,
                                                             List<MonitorInfoRecordDto> recordList, MonitorRecordVo monitorRecordVo) {
        final Date[] dataTime = {null, null};
        //转map备用
        Map<String, MonitorInfoRecordDto> mp = new HashMap<>();
        if (CollectionUtil.isNotEmpty(recordList)) {
            recordList.stream().forEach(c -> {
                String collectTime = c.getCollectTime();
                Date collectDate = DateUtil.parse(collectTime, DatePattern.NORM_DATETIME_MINUTE_FORMAT);
                if (dataTime[0] == null) {
                    dataTime[0] = collectDate;
                }
                if (dataTime[1] == null) {
                    dataTime[1] = collectDate;
                }
                if (dataTime[0].after(collectDate)) {
                    dataTime[0] = collectDate;
                }
                if (dataTime[1].before(collectDate)) {
                    dataTime[1] = collectDate;
                }
                mp.put(collectTime, c);
            });
        }
        TreeMap<String, MonitorInfoRecordDto> resMp = new TreeMap<>();
        Date start = dataTime[0];
        if (start == null) {
            start = DateUtil.beginOfHour(monitorRecordVo.getStartTime());
        }
        Date end = dataTime[1];
        if (end == null) {
            end = DateUtil.beginOfHour(monitorRecordVo.getEndTime());
        }
        while (start.before(end) || start.equals(end)) {
            String coTime = DateUtil.format(start, DatePattern.NORM_DATETIME_MINUTE_FORMAT);
            MonitorInfoRecordDto dto = mp.get(coTime);
            if (dto != null) {
                dto.setPointTime(start);
            }
            resMp.put(coTime, dto);

            start = getNextTime(start, rangeType, stepNum);
        }

        return resMp;
    }

    private Date getNextTime(Date start, String rangeType, Integer stepNum) {
        switch (rangeType) {
            case "d":
                break;
            case "h":
                start = DateUtil.offsetHour(start, stepNum);
                break;
            default:
                start = DateUtil.offsetMinute(start, stepNum);
                break;
        }
        return start;
    }

    /**
     * 处理时间范围
     *
     * @param rangeType       区间type
     * @param monitorRecordVo 监测recordvo
     */
    private void initDateRange(String rangeType, MonitorRecordVo monitorRecordVo) {
        if (monitorRecordVo.getStartTime() == null && monitorRecordVo.getEndTime() == null) {
            //Date now = DateUtil.beginOfHour(DateUtil.offsetHour(DateUtil.date(), 1));
            Date now = DateUtil.date();
            Date startTime = null;
            monitorRecordVo.setEndTime(now);
            switch (rangeType) {
                case "d":
                    //时间前推15日
                    startTime = DateUtil.offsetDay(now, -15);
                    break;
                case "h":
                    //时间前推24小时
                    startTime = DateUtil.offsetHour(now, -24);
                default:
                    startTime = DateUtil.offsetHour(now, -12);
                    break;
            }

            monitorRecordVo.setStartTime(startTime);
        }

    }
}
